#include <avr/io.h>
#include <inttypes.h>

#define DEBUG_MODE

#include "include/debug.h"
#include "include/SD.h"


#ifndef EXMEM
#define EXMEM __attribute__ ((section(".exram")))
#endif //EXMEM
void before_main(void)
__attribute__((naked))
__attribute__((section(".init3")));

void before_main(void)
{
    MCUCR = 1<<SRE;
    SFIOR = 1<<XMBK | 1<<XMM0;
    DDRC = 0x80;
    PORTC &= ~(1<<7);
}
sd_context_t sdc EXMEM;

void print_cid(sd_context_t * sdc)
{
    DEBUG_PRINT("MID = %02x\n",sdc->CID.MID);
    DEBUG_PRINT("OID = %c%c\n",sdc->CID.OID[0],sdc->CID.OID[1]);
    DEBUG_PRINT("Product Revision = %02x\n",sdc->CID.MID);
    DEBUG_PRINT("PSN = %02x%02x%02x%02x\n",sdc->CID.PSN[0],sdc->CID.PSN[1],sdc->CID.PSN[2],sdc->CID.PSN[3]);
    DEBUG_PRINT("PNM = %c%c%c%c%c\n",sdc->CID.PNM[0],sdc->CID.PNM[1],sdc->CID.PNM[2],sdc->CID.PNM[3],sdc->CID.PNM[4]);
    DEBUG_PRINT("MDT = %d.20%d%d\n",(sdc->CID.MDT>>8)&0xf,(sdc->CID.MDT)&0xf,(sdc->CID.MDT>>4)&0xf);
}

void print_csd(sd_context_t * sdc)
{
    DEBUG_PRINT("CSD:\n");
    DEBUG_PRINT("CSD:\n");
    DEBUG_PRINT("CSD structure: %x\n",SD_GET_CSD_STRUCTURE(sdc));
    DEBUG_PRINT("TAAC: %x\n",SD_GET_CSD_TAAC(sdc));
    DEBUG_PRINT("NSAC: %x\n",SD_GET_CSD_NSAC(sdc));
    DEBUG_PRINT("TRANS_SPEED: %x\n",SD_GET_CSD_TRANS_SPEED(sdc));
    DEBUG_PRINT("CCC: %x\n",SD_GET_CSD_CCC(sdc));
    DEBUG_PRINT("READ_BL_LEN: %x\n",SD_GET_CSD_READ_BL_LEN(sdc));
    DEBUG_PRINT("READ_BL_PARTIAL: %x\n",SD_GET_CSD_READ_BL_PARTIAL(sdc));
    DEBUG_PRINT("WRITE_BLK_MISSALIGN: %x\n",SD_GET_CSD_WRITE_BLK_MISSALIGN(sdc));
    DEBUG_PRINT("READ_BLK_MISSALIGN: %x\n",SD_GET_CSD_READ_BLK_MISSALIGN(sdc));
    DEBUG_PRINT("DSR_IMP: %x\n",SD_GET_CSD_DSR_IMP(sdc));
    DEBUG_PRINT("C_SIZE: %x\n",SD_GET_CSD_C_SIZE(sdc));
    DEBUG_PRINT("VDD_R_CURR_MIN: %x\n",SD_GET_CSD_VDD_R_CURR_MIN(sdc));
    DEBUG_PRINT("VDD_R_CURR_MAX: %x\n",SD_GET_CSD_VDD_R_CURR_MAX(sdc));
    DEBUG_PRINT("VDD_W_CURR_MIN: %x\n",SD_GET_CSD_VDD_W_CURR_MIN(sdc));
    DEBUG_PRINT("VDD_W_CURR_MAX: %x\n",SD_GET_CSD_VDD_W_CURR_MAX(sdc));
    DEBUG_PRINT("C_SIZE_MULT: %x\n",SD_GET_CSD_C_SIZE_MULT(sdc));
    DEBUG_PRINT("ERASE_BLK_EN: %x\n",SD_GET_CSD_ERASE_BLK_EN(sdc));
    DEBUG_PRINT("SECTOR_SIZE: %x\n",SD_GET_CSD_SECTOR_SIZE(sdc));
    DEBUG_PRINT("WP_GRP_SIZE: %x\n",SD_GET_CSD_WP_GRP_SIZE(sdc));
    DEBUG_PRINT("WP_GRP_ENABLE: %x\n",SD_GET_CSD_WP_GRP_ENABLE(sdc));
    DEBUG_PRINT("R2W_FACTOR: %x\n",SD_GET_CSD_R2W_FACTOR(sdc));
    DEBUG_PRINT("WRITE_BL_LEN: %x\n",SD_GET_CSD_WRITE_BL_LEN(sdc));
    DEBUG_PRINT("WRITE_BL_PARTIAL: %x\n",SD_GET_CSD_WRITE_BL_PARTIAL(sdc));
    DEBUG_PRINT("FILE_FORMAT_GRP: %x\n",SD_GET_CSD_FILE_FORMAT_GRP(sdc));
    DEBUG_PRINT("COPY: %x\n",SD_GET_CSD_COPY(sdc));
    DEBUG_PRINT("PERM_WRITE_PROTECT: %x\n",SD_GET_CSD_PERM_WRITE_PROTECT(sdc));
    DEBUG_PRINT("TMP_WRITE_PROTECT: %x\n",SD_GET_CSD_TMP_WRITE_PROTECT(sdc));
    DEBUG_PRINT("FILE_FORMAT: %x\n",SD_GET_CSD_FILE_FORMAT(sdc));
    DEBUG_PRINT("CRC: %x\n",SD_GET_CSD_CRC(sdc));    
}

int main(void)
{
    uint32_t retval;
    DEBUG_INIT();
    DEBUG_OUT("initializing SD Card...\n");

    sdc.R1 = 0;
    retval = sd_init(&sdc);
    switch(retval)
    {
      case 0:
	DEBUG_OUT("Success!\n");
	DEBUG_PRINT("R1= %x,OCR = 0x%02x%02x%02x%02x\n",sdc.R1,sdc.OCR[3],sdc.OCR[2],sdc.OCR[1],sdc.OCR[0]);
	print_cid(&sdc);
	print_csd(&sdc);
	//DEBUG_PRINT("SD size = %u\n",sd_size(&sdc));
	break;
      case sderr_BusError:
	DEBUG_OUT("sderr_BusError\n");
	break;
      case sderr_CardInit_NotInIdleState:
	DEBUG_OUT("sderr_CardInit_NotInIdleState\n");
	break;
      case sderr_CardInit_Timeout:
	DEBUG_OUT("sderr_CardInit_Timeout\n");
	break;
      case sderr_CardInit_ReadOCR:
	DEBUG_OUT("sderr_CardInit_ReadOCR\n");
	break;
      case sderr_CardReadCmd_Timeout:
	DEBUG_OUT("sderr_CardReadCmd_Timeout\n");
	break;
      case sderr_ReadCSDCID_Timeout:
	DEBUG_PRINT("sderr_ReadCID_Timeout\n");
	break;
      default:
	DEBUG_OUT("?\n");
	break;
    }
    for(;;)
    {
	/*
	 * Main loop
	 */
    }
    return 0;
}
